home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / quicktime / effects / qteffects explode / qteffects.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  19.8 KB  |  752 lines

  1. /*
  2.     File:        QTEffects.c
  3.     
  4.     Contains:    Code to generate a QuickTime movie with a QuickTime video effect in it.
  5.     
  6.     Written by:    Scott Kuechle
  7.                 (based heavily on QuickTime SDK QTShowEffect sample code by Tim Monroe)
  8.  
  9.     Copyright:    © 1999 by Apple Computer, Inc. All rights reserved
  10.     
  11.     Change History (most recent first)
  12.     
  13.         <1>        9/25/99        srk        first file
  14.         <2>        10/19/99    srk        changed cross fade effect to explode effect
  15.  
  16.  
  17. This file defines functions that create a QuickTime movie with a video effect as a transition
  18. from one picture to another. This project differs from the QTShowEffect sample code it is based 
  19. on in that it allows the user to create the effect "by hand" e.g. without the aid of the standard 
  20. QuickTime effects parameter dialog box. Instead, the program itself builds the correct effects 
  21. parameter description atoms.
  22.  
  23. Here's a quick rundown of how the program works:
  24.  
  25. • First, a QuickTime movie with two video tracks is created - these two tracks will be used as 
  26. sources for a explode video effect
  27.  
  28. • The effect description and sample description structures for the explode effect are created
  29.        
  30. • An effects track and media are created and added to our movie for the explode effect
  31.  
  32. • The input map for the effect is created, and references for the two video tracks are added to 
  33. this input map
  34.         
  35. The resulting movie, when played, will show a smooth alpha blending between the two video tracks.
  36.  
  37. */
  38.  
  39.  
  40. #ifndef __IMAGECODEC__
  41. #include <ImageCodec.h>
  42. #endif
  43.  
  44. #ifndef __MOVIES__
  45. #include <Movies.h>
  46. #endif
  47.  
  48. #ifndef __MOVIESFORMAT__
  49. #include <MoviesFormat.h>
  50. #endif
  51.  
  52. #ifndef __MEDIAHANDLERS__
  53. #include <MediaHandlers.h>
  54. #endif
  55.  
  56. #ifndef __NUMBERFORMATTING__
  57. #include <NumberFormatting.h>
  58. #endif
  59.  
  60. #ifndef __QUICKTIMECOMPONENTS__
  61. #include <QuickTimeComponents.h>
  62. #endif
  63.  
  64. #ifndef __ENDIAN__
  65. #include <Endian.h>
  66. #endif
  67.  
  68. #ifndef __GESTALT__
  69. #include <Gestalt.h>
  70. #endif
  71.  
  72. #ifndef __FIXMATH__
  73. #include <FixMath.h>
  74. #endif
  75.  
  76. #ifndef __MACWINDOWS__
  77. #include <MacWindows.h>
  78. #endif
  79.  
  80. #ifndef __PRINTING__
  81. #include <Printing.h>
  82. #endif
  83.  
  84. #ifndef __SCRIPT__
  85. #include <Script.h>
  86. #endif
  87.  
  88. #ifndef __SOUND__
  89. #include <Sound.h>
  90. #endif
  91.  
  92. #ifndef _STRING_H
  93. #include <string.h>
  94. #endif
  95.  
  96. #ifndef _STDLIB_H
  97. #include <stdlib.h>
  98. #endif
  99.  
  100. #ifndef __TEXTUTILS__
  101. #include <TextUtils.h>
  102. #endif
  103.  
  104. #ifndef __TRAPS__
  105. #include <Traps.h>
  106. #endif
  107.  
  108. #ifndef __RESOURCES__
  109. #include <Resources.h>
  110. #endif
  111.  
  112. #ifndef __FILETYPESANDCREATORS__
  113. #include <FileTypesAndCreators.h>
  114. #endif
  115.  
  116. #if TARGET_OS_WIN32
  117.         // Windows headers
  118.     #define    STRICT
  119.     #include <windows.h>
  120.         // QTML stuff
  121.     #include "QTML.h"
  122. #endif
  123.  
  124.  
  125. #include "QTEffects.h"
  126.  
  127.  
  128. // miscellaneous constants
  129.  
  130. #define kSourceOneName                    FOUR_CHAR_CODE('srcA')
  131. #define kSourceTwoName                    FOUR_CHAR_CODE('srcB')
  132. #define kSourceNoneName                    FOUR_CHAR_CODE('srcZ')
  133.  
  134. #define kPictGWorldDepth                32
  135.  
  136. #define kPict1ResID                        128
  137. #define kPict2ResID                        129
  138.  
  139. #define kPrompt                            "Specify a new movie file name:"
  140. #define kMovieFileName                    "Movie File.mov"
  141.  
  142. #define kOneSecond                        600
  143. #define kEffectMovieDuration            (3 * kOneSecond)
  144.  
  145. #define kTrackDisplayWidth                 200
  146. #define kTrackDisplayHeight             240
  147.  
  148. #define FAIL_OSERR(y)                    if (y != noErr) {goto bail;}
  149.  
  150.  
  151.  
  152. ////////////////////
  153. //
  154. // QTEffects_GetPictResourceAsGWorld
  155. // Create a new GWorld of the specified size and bit depth; then draw the specified PICT resource into it.
  156. // The new GWorld is returned through the theGW parameter.
  157. //
  158. ////////////////////
  159.  
  160. Movie QTEffects_CreateEffectsMovie()
  161. {
  162.     Movie                     theMovie = nil;
  163.     short                     resRefNum = 0;
  164.     short                     resId = movieInDataForkResID;    
  165.     OSErr                     myErr = noErr;
  166.     Track                    sourceTrack1, sourceTrack2;
  167.     ImageDescriptionHandle    mySampleDesc = NULL;
  168.     QTAtomContainer         theEffectDesc;
  169.     Track                    myTrack;
  170.     Media                    myMedia;
  171.     FSSpec                    movieFSSpec;
  172.  
  173.     /* Let's first create a movie file with two video tracks. Each
  174.         video track will be used as a source for our explode effect */
  175.     QTEffects_CreateTwoTrackMovie(    &theMovie,
  176.                                     &resRefNum,
  177.                                     &movieFSSpec,
  178.                                     &sourceTrack1,
  179.                                     &sourceTrack2);
  180.  
  181.     /* Setup the effect description and sample description for our cross
  182.        fade effect */
  183.     QTEffects_SetupEffectsDescription(  kExplodeTransitionType/*kCrossFadeTransitionType*/,
  184.                                         &mySampleDesc,
  185.                                         &theEffectDesc);
  186.  
  187.     /* Create and add an effects track and media to our movie for the cross
  188.         fade effect */
  189.     QTEffects_CreateEffectsTrackAndMedia(   theMovie,
  190.                                             mySampleDesc,
  191.                                             theEffectDesc,
  192.                                             &myTrack,
  193.                                             &myMedia);
  194.  
  195.     /* Create the input map for the effect, and add references for the two
  196.         video tracks */
  197.     QTEffects_CreateInputMapAndAddTrackReferences(  myTrack,
  198.                                                     myMedia,
  199.                                                     sourceTrack1,
  200.                                                     sourceTrack2);
  201.  
  202.  
  203.     /* save our changes to the movie */
  204.  
  205.     myErr = AddMovieResource (theMovie,
  206.                                 resRefNum,
  207.                                 &resId,
  208.                                  nil);
  209.  
  210.     DisposeMovie(theMovie);
  211.  
  212.  
  213.     if (mySampleDesc != NULL)
  214.         DisposeHandle((Handle)mySampleDesc);
  215.         
  216.     return theMovie;
  217. }
  218.  
  219. ////////////////////
  220. //
  221. // QTEffects_CreateTwoTrackMovie
  222. // 
  223. // Create a movie with two video tracks. Each track is based on our stored picture files.
  224. // The two tracks will be used as sources for our two-source explode effect.
  225. //
  226. ////////////////////
  227.  
  228. static void QTEffects_CreateTwoTrackMovie( Movie *theMovie,
  229.                                             short    *resRefNum,
  230.                                             FSSpec    *movieFSSpec,
  231.                                             Track    *videoTrack1,
  232.                                             Track    *videoTrack2)
  233. {
  234.     Point         where = {100,100};
  235.     SFReply     theSFReply;
  236.     OSErr         myErr = noErr;
  237.     GWorldPtr    offscreenGWorld1,offscreenGWorld2;
  238.     
  239.  
  240.         /* Let's first create a movie file */
  241.  
  242.     SFPutFile (where, c2pstr(kPrompt), 
  243.                 c2pstr(kMovieFileName), nil, &theSFReply);
  244.     if (!theSFReply.good) return; 
  245.  
  246.     FSMakeFSSpec(theSFReply.vRefNum, 0, theSFReply.fName, movieFSSpec);
  247.  
  248.     myErr = CreateMovieFile (movieFSSpec, 
  249.                             sigMoviePlayer,
  250.                             smCurrentScript, 
  251.                             createMovieFileDeleteCurFile | createMovieFileDontCreateResFile,
  252.                             resRefNum, 
  253.                             theMovie);
  254.     FAIL_OSERR(myErr);
  255.     
  256.         /* Now we'll retrieve some stored pictures which will be used in the creation of our video tracks */ 
  257.  
  258.     myErr =  QTEffects_GetPictResourceAsGWorld (kPict1ResID, kTrackDisplayWidth, kTrackDisplayHeight, kPictGWorldDepth, &offscreenGWorld1);
  259.     FAIL_OSERR(myErr);
  260.     
  261.     myErr =  QTEffects_GetPictResourceAsGWorld (kPict2ResID,  kTrackDisplayWidth, kTrackDisplayHeight, kPictGWorldDepth, &offscreenGWorld2);
  262.     FAIL_OSERR(myErr);
  263.  
  264.  
  265.         /* Now add two video tracks to our movie, based on the source pictures just retrieved. 
  266.         
  267.            Note: video tracks used as sources for an effect should start at the same time as the effect
  268.            track and end at the same time as the effect track
  269.            
  270.         */
  271.        
  272.     myErr = QTEffects_AddVideoTrackFromGWorld(theMovie, offscreenGWorld1, videoTrack1, 0, kTrackDisplayWidth, kTrackDisplayHeight);
  273.     FAIL_OSERR(myErr);
  274.  
  275.     myErr = QTEffects_AddVideoTrackFromGWorld(theMovie, offscreenGWorld2, videoTrack2, 0, kTrackDisplayWidth, kTrackDisplayHeight);
  276.     FAIL_OSERR(myErr);
  277.  
  278.  
  279.     bail:
  280.     ;
  281.     
  282. }
  283.  
  284.                                         
  285.  
  286. ////////////////////
  287. //
  288. // QTEffects_GetPictResourceAsGWorld
  289. // Create a new GWorld of the specified size and bit depth; then draw the specified PICT resource into it.
  290. // The new GWorld is returned through the theGW parameter.
  291. //
  292. ////////////////////
  293.  
  294. static OSErr QTEffects_GetPictResourceAsGWorld (short theResID, short theWidth, short theHeight, short theDepth, GWorldPtr *theGW)
  295. {
  296.     PicHandle                myHandle = NULL;
  297.     PixMapHandle            myPixMap = NULL;
  298.     CGrafPtr                mySavedPort;
  299.     GDHandle                mySavedDevice;
  300.     Rect                    myRect;
  301.     OSErr                    myErr = noErr;
  302.  
  303.     // get the current drawing environment
  304.     GetGWorld(&mySavedPort, &mySavedDevice);
  305.  
  306.     // read the specified PICT resource from the application's resource file
  307.     myHandle = GetPicture(theResID);
  308.     if (myHandle == NULL) {
  309.         myErr = ResError();
  310.         if (myErr == noErr)
  311.             myErr = resNotFound;
  312.         goto bail;
  313.     }
  314.  
  315.     // set the size of the GWorld
  316.     MacSetRect(&myRect, 0, 0, theWidth, theHeight);
  317.  
  318.     // allocate a new GWorld
  319.     myErr = QTNewGWorld(theGW, theDepth, &myRect, NULL, NULL, kICMTempThenAppMemory);
  320.     FAIL_OSERR(myErr);
  321.     
  322.     SetGWorld(*theGW, NULL);
  323.  
  324.     // get a handle to the offscreen pixel image and lock it
  325.     myPixMap = GetGWorldPixMap(*theGW);
  326.     LockPixels(myPixMap);
  327.  
  328.     EraseRect(&myRect);
  329.     DrawPicture(myHandle, &myRect);
  330.     
  331.     if (myPixMap != NULL)
  332.         UnlockPixels(myPixMap);
  333.     
  334. bail:
  335.     // restore the previous port and device
  336.     SetGWorld(mySavedPort, mySavedDevice);
  337.  
  338.     if (myHandle != NULL)
  339.         ReleaseResource((Handle)myHandle);
  340.     
  341.     return(myErr);
  342. }
  343.  
  344.  
  345. ////////////////////
  346. //
  347. // QTEffects_AddVideoTrackFromGWorld
  348. // Add to the specified movie a video track for the specified picture resource.
  349. //
  350. ////////////////////
  351.  
  352. static OSErr QTEffects_AddVideoTrackFromGWorld (Movie *theMovie, GWorldPtr theGW, Track *theSourceTrack, long theStartTime, short theWidth, short theHeight)
  353. {
  354.     Media                        myMedia;
  355.     ImageDescriptionHandle        myDesc = NULL;
  356.     Rect                        myRect;
  357.     long                        mySize;
  358.     Handle                        myData = NULL;
  359.     Ptr                            myDataPtr = NULL;
  360.     GWorldPtr                    myGWorld = NULL;
  361.     CGrafPtr                     mySavedPort = NULL;
  362.     GDHandle                     mySavedGDevice = NULL;
  363.     PicHandle                    myHandle = NULL;
  364.     PixMapHandle                mySrcPixMap = NULL;
  365.     PixMapHandle                myDstPixMap = NULL;
  366.     OSErr                        myErr = noErr;
  367.     
  368.     // get the current port and device
  369.     GetGWorld(&mySavedPort, &mySavedGDevice);
  370.     
  371.     // create a video track in the movie
  372.     *theSourceTrack = NewMovieTrack(*theMovie, FixRatio(theWidth, 1), FixRatio(theHeight, 1), kNoVolume);
  373.     myMedia = NewTrackMedia(*theSourceTrack, VideoMediaType, kOneSecond, NULL, 0);
  374.     
  375.     // get the rectangle for the movie
  376.     GetMovieBox(*theMovie, &myRect);
  377.     
  378.     // begin editing the new track
  379.     BeginMediaEdits(myMedia);
  380.         
  381.     // create a new GWorld; we draw the picture into this GWorld and then compress it
  382.     // (note that we are creating a picture with the maximum bit depth)
  383.     myErr = NewGWorld(&myGWorld, kPictGWorldDepth, &myRect, NULL, NULL, 0L);
  384.     FAIL_OSERR(myErr);
  385.     
  386.     mySrcPixMap = GetGWorldPixMap(theGW);
  387.     // LockPixels(mySrcPixMap);
  388.     
  389.     myDstPixMap = GetGWorldPixMap(myGWorld);
  390.     LockPixels(myDstPixMap);
  391.     
  392.     // create a new image description; CompressImage will fill in the fields of this structure
  393.     myDesc = (ImageDescriptionHandle)NewHandle(4);
  394.     
  395.     SetGWorld(myGWorld, NULL);
  396.     
  397.     // copy the image from the specified GWorld into the new GWorld
  398.     CopyBits((BitMap *)(*mySrcPixMap), (BitMap *)(*myDstPixMap), &(theGW->portRect), &(myGWorld->portRect), srcCopy, 0L);
  399.  
  400.     // restore the original port and device
  401.     SetGWorld(mySavedPort, mySavedGDevice);
  402.     
  403.     myErr = GetMaxCompressionSize(myDstPixMap, &myRect, 0, codecNormalQuality, kAnimationCodecType, anyCodec, &mySize);
  404.     FAIL_OSERR(myErr);
  405.         
  406.     myData = NewHandle(mySize);
  407.     FAIL_OSERR(myErr);
  408.         
  409.     HLockHi(myData);
  410.     myDataPtr = StripAddress(*myData);
  411.     
  412.     myErr = CompressImage(myDstPixMap, &myRect, codecNormalQuality, kAnimationCodecType, myDesc, myDataPtr);
  413.     FAIL_OSERR(myErr);
  414.         
  415.     myErr = AddMediaSample(myMedia, myData, 0, (**myDesc).dataSize, kEffectMovieDuration, (SampleDescriptionHandle)myDesc, 1, 0, NULL);
  416.     FAIL_OSERR(myErr);
  417.  
  418.     myErr = EndMediaEdits(myMedia);
  419.     FAIL_OSERR(myErr);
  420.  
  421.     myErr = InsertMediaIntoTrack(*theSourceTrack, theStartTime, 0, GetMediaDuration(myMedia), fixed1);
  422.     
  423. bail:
  424.     // restore the original port and device
  425.     SetGWorld(mySavedPort, mySavedGDevice);
  426.     
  427.     if (myData != NULL) {
  428.         HUnlock(myData);
  429.         DisposeHandle(myData);
  430.     }
  431.  
  432.     if (myDesc != NULL)
  433.         DisposeHandle((Handle)myDesc);
  434.         
  435.     // if (mySrcPixMap != NULL)
  436.     //     UnlockPixels(mySrcPixMap);
  437.         
  438.     if (myDstPixMap != NULL)
  439.         UnlockPixels(myDstPixMap);
  440.         
  441.     if (myGWorld != NULL)
  442.         DisposeGWorld(myGWorld);
  443.     
  444.     return(myErr);
  445. }
  446.  
  447.  
  448. ////////////////////
  449. //
  450. // QTEffects_SetupEffectsDescription
  451. // Create the effect description and sample description for the effect.
  452. //
  453. ////////////////////
  454.  
  455. static void QTEffects_SetupEffectsDescription( OSType                    theEffectType,
  456.                                                 ImageDescriptionHandle    *mySampleDesc,
  457.                                                 QTAtomContainer         *theEffectDesc)
  458. {
  459.     // set up a new effect description
  460.     QTEffects_CreateEffectDescription(theEffectType, kSourceOneName, kSourceTwoName, theEffectDesc);
  461.  
  462.     // set up the effects parameters for the explode effect 
  463.     QTEffects_CreateEffectParameterForExplode(*theEffectDesc);
  464.  
  465.     // create an effect sample description
  466.     *mySampleDesc = QTEffects_MakeSampleDescription(theEffectType, kTrackDisplayWidth, kTrackDisplayHeight);
  467.  
  468. }
  469.  
  470.  
  471. ////////////////////
  472. //
  473. // QTEffects_CreateEffectsTrackAndMedia
  474. // Create an effects track and associated media for our movie.
  475. //
  476. ////////////////////
  477.  
  478.  
  479.  
  480. static void QTEffects_CreateEffectsTrackAndMedia(Movie myMovie, 
  481.                                             ImageDescriptionHandle    mySampleDesc,
  482.                                             QTAtomContainer         theEffectDesc,
  483.                                             Track *myTrack,
  484.                                             Media *myMedia)
  485. {
  486.     OSErr         myErr;
  487.     TimeValue    mySampleTime;
  488.  
  489.  
  490.     *myTrack = NewMovieTrack(myMovie, FixRatio(kTrackDisplayWidth, 1), FixRatio(kTrackDisplayHeight, 1), kNoVolume);
  491.     myErr = GetMoviesError();
  492.     FAIL_OSERR(myErr);
  493.     
  494.     *myMedia = NewTrackMedia(*myTrack, VideoMediaType, kOneSecond, NULL, 0);
  495.     myErr = GetMoviesError();
  496.     FAIL_OSERR(myErr);
  497.  
  498.     // add the effect description as a sample to the effect track media
  499.     myErr = BeginMediaEdits(*myMedia);
  500.     FAIL_OSERR(myErr);
  501.  
  502.     myErr = AddMediaSample(*myMedia,
  503.                             (Handle)theEffectDesc,
  504.                             0,
  505.                             GetHandleSize((Handle)theEffectDesc),
  506.                             kEffectMovieDuration,
  507.                             (SampleDescriptionHandle)mySampleDesc,
  508.                             1,
  509.                             0,
  510.  
  511.                             &mySampleTime);
  512.     FAIL_OSERR(myErr);
  513.  
  514.  
  515.     myErr = EndMediaEdits(*myMedia);
  516.     FAIL_OSERR(myErr);
  517.  
  518.     // add the media to the track
  519.     myErr = InsertMediaIntoTrack(*myTrack, 0, mySampleTime, GetMediaDuration(*myMedia), fixed1);
  520.     FAIL_OSERR(myErr);
  521.  
  522. bail:
  523. ;
  524.  
  525.  
  526. }
  527.  
  528.  
  529. ////////////////////
  530. //
  531. // QTEffects_CreateInputMapAndAddTrackReferences
  532. // Create an input map, and add references to the input map for both
  533. // video tracks.
  534. //
  535. ////////////////////
  536.  
  537. static void QTEffects_CreateInputMapAndAddTrackReferences(Track effectsTrack,
  538.                                                     Media    effectsTrackMedia,
  539.                                                     Track     sourceTrack1,
  540.                                                     Track     sourceTrack2)
  541. {
  542.     QTAtomContainer myInputMap;
  543.     OSErr             myErr;
  544.  
  545.  
  546.  
  547.     // create the input map
  548.     myErr = QTNewAtomContainer(&myInputMap);
  549.     FAIL_OSERR(myErr);
  550.  
  551.     // add references for the two video tracks
  552.     myErr = QTEffects_AddTrackReferenceToInputMap(myInputMap, effectsTrack, sourceTrack1, kSourceOneName);
  553.     FAIL_OSERR(myErr);
  554.  
  555.     // try using existing video track as source
  556.     myErr = QTEffects_AddTrackReferenceToInputMap(myInputMap, effectsTrack, sourceTrack2, kSourceTwoName);
  557.     FAIL_OSERR(myErr);
  558.  
  559.     // add the input map to the effects track
  560.     myErr = SetMediaInputMap(effectsTrackMedia, myInputMap);
  561.     FAIL_OSERR(myErr);
  562.     
  563.  
  564. bail:
  565. ;
  566.     if (myInputMap != NULL)
  567.     QTDisposeAtomContainer(myInputMap);
  568.  
  569. }
  570.  
  571.  
  572.  
  573. ////////////////////
  574. //
  575. // QTEffects_CreateEffectDescription
  576. // Create an effect description for zero, one, or two sources.
  577. // 
  578. // The effect description specifies which video effect is desired and the parameters for that effect.
  579. // It also describes the source(s) for the effect. An effect description is simply an atom container
  580. // that holds atoms with the appropriate information.
  581. //
  582. // Note that because we are creating an atom container, we must pass big-endian data (hence the calls
  583. // to EndianU32_NtoB).
  584. //
  585. // The caller is responsible for disposing of the returned atom container, by calling QTDisposeAtomContainer.
  586. //
  587. ////////////////////
  588.  
  589. static void QTEffects_CreateEffectDescription (OSType            theEffectName,
  590.  
  591.                                               OSType            theSourceName1,
  592.  
  593.                                               OSType            theSourceName2,
  594.  
  595.                                               QTAtomContainer    *theEffectDesc)
  596. {
  597.     OSType                myType;
  598.     OSErr                myErr = noErr;
  599.  
  600.  
  601.  
  602.     // create a new, empty effect description
  603.     myErr = QTNewAtomContainer(theEffectDesc);
  604.     FAIL_OSERR(myErr);
  605.  
  606.     // create the effect ID atom: the atom type is kParameterWhatName, and the atom ID is kParameterWhatID
  607.     myType = EndianU32_NtoB(theEffectName);
  608.     myErr = QTInsertChild(*theEffectDesc, kParentAtomIsContainer, kParameterWhatName, kParameterWhatID, 0, sizeof(myType), &myType, NULL);
  609.     FAIL_OSERR(myErr);
  610.         
  611.     // add the first source, if it's not kSourceNoneName
  612.     if (theSourceName1 != kSourceNoneName) {
  613.         myType = EndianU32_NtoB(theSourceName1);
  614.         myErr = QTInsertChild(*theEffectDesc, kParentAtomIsContainer, kEffectSourceName, 1, 0, sizeof(myType), &myType, NULL);
  615.         FAIL_OSERR(myErr);
  616.     }
  617.                             
  618.     // add the second source, if it's not kSourceNoneName
  619.     if (theSourceName2 != kSourceNoneName) {
  620.         myType = EndianU32_NtoB(theSourceName2);
  621.         myErr = QTInsertChild(*theEffectDesc, kParentAtomIsContainer, kEffectSourceName, 2, 0, sizeof(myType), &myType, NULL);
  622.     }
  623.  
  624.  
  625. bail:
  626. ;
  627.  
  628. }
  629.  
  630. ////////////////////
  631. //
  632. // QTEffects_CreateEffectParameterForExplode
  633. // Create the parameter atoms for the Explode effect. This will include a
  634. // percentage atom, along with a tween atom to tween the effect, plus atoms
  635. // specifying the x & y coordinates of the explosion centre.
  636. //
  637. ////////////////////
  638.  
  639. static void QTEffects_CreateEffectParameterForExplode(QTAtomContainer myEffectDesc)
  640. {
  641.     Fixed    percentage[2];
  642.     Fixed     explodeCentreX,explodeCentreY;
  643.     OSErr    myErr = noErr;
  644.     QTAtom    newAtom;
  645.     OSType    tweenType;
  646.  
  647.  
  648.  
  649.     /* add the percentage ('pcnt') atom for the effect */
  650.     myErr = QTInsertChild(myEffectDesc, kParentAtomIsContainer, kParameterUsagePercent, 1, 0, 0, 0, &newAtom);
  651.     FAIL_OSERR(myErr);
  652.  
  653.     /* this atom specifies the format of the tween data */
  654.  
  655.     tweenType = EndianU32_NtoB(kParameterTypeDataFixed);
  656.     myErr = QTInsertChild(myEffectDesc, newAtom, kTweenType, 1 , 0, sizeof(OSType), &tweenType, NULL);
  657.     FAIL_OSERR(myErr);
  658.  
  659.     /* here's the data for the tween  */
  660.  
  661.     percentage[0] =  EndianS32_NtoB( X2Fix(0.90) );    /* 90% */
  662.  
  663.     percentage[1] =  EndianS32_NtoB( X2Fix(0.10) );    /* 20% */
  664.     myErr = QTInsertChild(myEffectDesc, newAtom, kTweenData, 1 , 0, sizeof(long) * 2, &percentage, NULL);
  665.  
  666.  
  667.     /* Add Explode X Centre atom */
  668.  
  669.     explodeCentreX =  EndianS32_NtoB( X2Fix(0.0) );
  670.     myErr = QTInsertChild(myEffectDesc, kParentAtomIsContainer, 'xcnt', 1, 0, sizeof(long), &explodeCentreX, 0);
  671.     FAIL_OSERR(myErr);
  672.  
  673.  
  674.     /* Add Explode Y Centre atom */
  675.  
  676.     explodeCentreY =  EndianS32_NtoB( X2Fix(0.0) );
  677.     myErr = QTInsertChild(myEffectDesc, kParentAtomIsContainer, 'ycnt', 1, 0, sizeof(long), &explodeCentreY, 0);
  678.     FAIL_OSERR(myErr);
  679.  
  680.     bail:
  681.     ;
  682. }
  683.  
  684.  
  685. ////////////////////
  686. //
  687. // QTEffects_MakeSampleDescription
  688. // Return a new image description with default and specified values.
  689. // 
  690. ////////////////////
  691.  
  692. static ImageDescriptionHandle QTEffects_MakeSampleDescription (OSType theEffectType, short theWidth, short theHeight)
  693. {
  694.     ImageDescriptionHandle        mySampleDesc = NULL;
  695.  
  696.     // create a new sample description
  697.     mySampleDesc = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
  698.     if (mySampleDesc == NULL)
  699.         return(NULL);
  700.     
  701.     // fill in the fields of the sample description
  702.     (**mySampleDesc).idSize = sizeof(ImageDescription);
  703.     (**mySampleDesc).cType = theEffectType;
  704.     (**mySampleDesc).vendor = kAppleManufacturer;
  705.     (**mySampleDesc).temporalQuality = codecNormalQuality;
  706.     (**mySampleDesc).spatialQuality = codecNormalQuality;
  707.     (**mySampleDesc).width = theWidth;
  708.     (**mySampleDesc).height = theHeight;
  709.     (**mySampleDesc).hRes = 72L << 16;
  710.     (**mySampleDesc).vRes = 72L << 16;
  711.     (**mySampleDesc).frameCount = 1;
  712.     (**mySampleDesc).depth = 0;
  713.     (**mySampleDesc).clutID = -1;
  714.     
  715.     return(mySampleDesc);
  716. }
  717.  
  718.  
  719.  
  720. ////////////////////
  721. //
  722. // QTEffects_AddTrackReferenceToInputMap
  723. // Add a track reference to the specified input map.
  724. // 
  725. ////////////////////
  726.  
  727. static OSErr QTEffects_AddTrackReferenceToInputMap (QTAtomContainer theInputMap, Track theTrack, Track theSrcTrack, OSType theSrcName)
  728. {
  729.     OSErr                myErr = noErr;
  730.     QTAtom                myInputAtom;
  731.     long                myRefIndex;
  732.     OSType                myType;
  733.  
  734.     myErr = AddTrackReference(theTrack, theSrcTrack, kTrackModifierReference, &myRefIndex);
  735.     FAIL_OSERR(myErr);
  736.             
  737.     // add a reference atom to the input map
  738.     myErr = QTInsertChild(theInputMap, kParentAtomIsContainer, kTrackModifierInput, myRefIndex, 0, 0, NULL, &myInputAtom);
  739.     FAIL_OSERR(myErr);
  740.     
  741.     // add two child atoms to the parent reference atom
  742.     myType = EndianU32_NtoB(kTrackModifierTypeImage);
  743.     myErr = QTInsertChild(theInputMap, myInputAtom, kTrackModifierType, 1, 0, sizeof(myType), &myType, NULL);
  744.     FAIL_OSERR(myErr);
  745.     
  746.     myType = EndianU32_NtoB(theSrcName);
  747.     myErr = QTInsertChild(theInputMap, myInputAtom, kEffectDataSourceType, 1, 0, sizeof(myType), &myType, NULL);
  748.         
  749. bail:
  750.     return(myErr);
  751. }
  752.